<!--这个版本主要是出现添加请求参数不会被封装到请求体里去-->
<template>
  <Navbar style="margin-bottom: 40px"></Navbar>
  <div class="container">
    <n-card>
      <h2>接口在线体验</h2>
      <n-space vertical size="large">
        <!-- 接口信息显示 -->
        <div v-if="interfaceInfo">
          <n-space align="center">
            <n-avatar size="80" src="https://via.placeholder.com/80" />
            <div>
              <h3>
                {{ interfaceInfo.name }}
                <n-icon>
                  <flame-outline />
                </n-icon>
                调用次数：{{ interfaceInfo.visitedCount }}
              </h3>
              <div>
                <span>{{ interfaceInfo.url }}</span>
                <n-button type="info" size="tiny" @click="copyText(interfaceInfo.url)">copy</n-button>
              </div>
              <p>{{ interfaceInfo.description }}</p>
            </div>
          </n-space>
          <n-space align="center">
            <n-tag :style="methodTagStyle">{{ interfaceInfo.method }}</n-tag>
            <n-input v-model:value="parameters.url" placeholder="请求 URL" style="width: 500px;" />
          </n-space>
        </div>

        <!-- 参数说明 -->
        <div v-if="interfaceInfo">
          <h3>参数说明</h3>
          <div v-if="paramDescription">
            <n-input type="textarea" v-model:value="paramDescription" readonly />
          </div>
          <div v-else>该接口未提供参数说明</div>
          <n-divider />
        </div>

        <!-- 请求头参数输入 -->
        <div v-if="interfaceInfo">
          <h3>请求头参数</h3>
          <n-space vertical>
            <n-table>
              <thead>
              <tr>
                <th>参数名</th>
                <th>参数值</th>
                <th>操作</th>
              </tr>
              </thead>
              <tbody>
              <tr v-for="(param, index) in parameters.headers" :key="index">
                <td>
                  <n-input v-model:value="param.name" />
                </td>
                <td>
                  <n-input v-model:value="param.value" />
                </td>
                <td>
                  <n-button type="error" @click="deleteHeaderParam(index)">删除</n-button>
                </td>
              </tr>
              </tbody>
            </n-table>
            <n-button @click="addHeaderParam">添加请求头参数</n-button>
          </n-space>
        </div>

        <!-- 请求参数输入 -->
        <div v-if="interfaceInfo">
          <h3>请求参数</h3>
          <n-space vertical>
            <n-table>
              <thead>
              <tr>
                <th>参数名</th>
                <th>参数值</th>
                <th>操作</th>
              </tr>
              </thead>
              <tbody>
              <tr v-for="(param, index) in parameters.queryParams" :key="index">
                <td>
                  <n-input v-model:value="param.name" />
                </td>
                <td>
                  <n-input v-model:value="param.value" />
                </td>
                <td>
                  <n-button type="error" @click="deleteQueryParam(index)">删除</n-button>
                </td>
              </tr>
              </tbody>
            </n-table>
            <n-button @click="addQueryParam">添加请求参数</n-button>
          </n-space>
        </div>

        <!-- 请求体 -->
        <div v-if="interfaceInfo">
          <h3>请求体</h3>
          <n-input type="textarea" v-model:value="requestBody" placeholder="输入 JSON 请求体" />
        </div>

        <!-- 文件参数 -->
        <div v-if="interfaceInfo">
          <h3>文件参数</h3>
          <n-space vertical>
            <n-table>
              <thead>
              <tr>
                <th>参数名</th>
                <th>文件</th>
                <th>操作</th>
              </tr>
              </thead>
              <tbody>
              <tr v-for="(file, index) in parameters.files" :key="index">
                <td>
                  <n-input v-model:value="file.name" />
                </td>
                <td>
                  <n-upload v-model:file-list="file.list" :on-before-upload="() => false">
                    <n-button>上传文件</n-button>
                  </n-upload>
                </td>
                <td>
                  <n-button type="error" @click="deleteFileParam(index)">删除</n-button>
                </td>
              </tr>
              </tbody>
            </n-table>
            <n-button @click="addFileParam">添加文件参数</n-button>
          </n-space>
        </div>

        <!-- 发送请求按钮 -->
        <n-button type="primary" @click="sendRequest">发送请求</n-button>

        <!-- 响应显示 -->
        <div v-if="response">
          <h3>响应结果</h3>
          <n-code :code="response" language="json" />
        </div>

        <!-- 请求历史记录 -->
        <div>
          <h3>请求历史</h3>
          <n-list>
            <n-list-item v-for="(history, index) in historyList" :key="index">
              <n-space>
                <span>{{ history.url }}</span>
                <n-button @click="viewHistory(index)">查看</n-button>
              </n-space>
            </n-list-item>
          </n-list>
        </div>

        <!-- 错误信息显示 -->
        <div v-if="error">
          <n-alert type="error" :closable="false">
            {{ error }}
          </n-alert>
        </div>
      </n-space>
    </n-card>
  </div>
</template>

<script>
import { ref, onMounted, DeprecationTypes } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import {
  NButton, NCard, NCode, NInput, NList, NListItem, NSpace, NAlert, NTag, NUpload, NAvatar, NDivider, useMessage, NIcon
} from 'naive-ui'
import { FlameOutline } from '@vicons/ionicons5'
import axios from 'axios'
import Navbar from '@/components/Navbar.vue'
import apiClient from '@/api/axios.ts'
import { useAuthStore } from '@/stores/auth.ts'

export default {
  components: {
    Navbar,
    NButton,
    NCard,
    NCode,
    NInput,
    NList,
    NListItem,
    NSpace,
    NAlert,
    NTag,
    NUpload,
    NAvatar,
    NDivider,
    NIcon,
    FlameOutline
  },
  setup() {
    const route = useRoute()
    const router = useRouter()
    const authStore = useAuthStore()
    const interfaceId = route.params.interfaceId
    console.log("接口在线调用页面加载中~，读取的接口id:" + interfaceId)

    const interfaceInfo = ref(null)
    const parameters = ref({
      url: '',
      headers: [],
      queryParams: [],
      files: []
    })
    const requestBody = ref('')
    const response = ref(null)
    const error = ref(null)
    const historyList = ref([])
    const message = useMessage()

    const fetchInterfaceInfo = async () => {
      try {
        const res = await apiClient.get(`/interfaceInfo/get?id=${interfaceId}`)
        interfaceInfo.value = res.data.data
        parameters.value.url = interfaceInfo.value.url
        // console.log("parameters.value.url  = " + parameters.value.url )
        parameters.value.headers = [] // 初始化请求头参数列表
        parameters.value.queryParams = [] // 初始化查询参数列表
        parameters.value.files = [] // 初始化文件参数列表
      } catch (err) {
        error.value = '获取接口信息失败'
      }
    }


    // @DeprecationTypes
    // const checkLogin = async () => {
    //   try {
    //     const res = await apiClient.get('/user/check-login')
    //     return res.data.loggedIn
    //   } catch (err) {
    //     return false
    //   }
    // }

    onMounted(() => {
      fetchInterfaceInfo()
    })

    const addHeaderParam = () => {
      parameters.value.headers.push({ name: '', value: '' })
    }

    const deleteHeaderParam = (index) => {
      parameters.value.headers.splice(index, 1)
    }

    const addQueryParam = () => {
      parameters.value.queryParams.push({ name: '', value: '' })
    }

    const deleteQueryParam = (index) => {
      parameters.value.queryParams.splice(index, 1)
    }

    const addFileParam = () => {
      parameters.value.files.push({ name: '', list: [] })
    }

    const deleteFileParam = (index) => {
      parameters.value.files.splice(index, 1)
    }

    const copyText = async (text) => {
      try {
        await navigator.clipboard.writeText(text)
        message.success('已复制到剪贴板')
      } catch (err) {
        message.error('复制失败')
      }
    }



    const sendRequest = async () => {
      const loggedIn = authStore.checkLogin()
      if (!loggedIn) {
        await router.push('/user/login')
        return
      }

      error.value = null
      response.value = null

      const requestData = {
        interfaceId: interfaceId,
        url: parameters.value.url,
        headers: parameters.value.headers.reduce((acc, param) => {
          acc[param.name] = param.value
          return acc
        }, {}),
        queryParams: parameters.value.queryParams.reduce((acc, param) => {
          acc[param.name] = param.value
          return acc
        }, {}),
        requestBody: requestBody.value,
        files: parameters.value.files.reduce((acc, file) => {
          acc[file.name] = file.list.length > 0 ? file.list[0] : null
          return acc
        }, {})
      }

      try {
        const res = await apiClient.post('/interface/invoke', requestData)
        response.value = res.data
        historyList.value.push({ url: parameters.value.url, queryParams: requestData.queryParams, requestBody: requestBody.value, response: res.data })
      } catch (err) {
        error.value = err.message
      }
    }

    const viewHistory = (index) => {
      const history = historyList.value[index]
      parameters.value.url = history.url
      parameters.value.queryParams = Object.keys(history.queryParams).map((key) => ({
        name: key,
        value: history.queryParams[key]
      }))
      requestBody.value = history.requestBody
      response.value = history.response
    }

    const methodTagStyle = {
      backgroundColor: '#FF5733',
      color: '#fff',
      padding: '5px 10px',
      borderRadius: '4px',
      fontWeight: 'bold'
    }

    const paramDescription = ref('')

    return {
      interfaceInfo,
      parameters,
      requestBody,
      response,
      error,
      historyList,
      addHeaderParam,
      deleteHeaderParam,
      addQueryParam,
      deleteQueryParam,
      addFileParam,
      deleteFileParam,
      copyText,
      sendRequest,
      viewHistory,
      methodTagStyle,
      paramDescription
    }
  }
}
</script>

<style scoped>
.container {
  max-width: 1000px;
  margin: 0 auto;
  padding: 2rem;
}
</style>
